package cn.iocoder.yudao.module.infra.framework.file.core.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import static cn.iocoder.yudao.module.infra.framework.file.core.client.chevereto.CheveretoFileClient.DEFAULT_COMPRESS_SIZE_THRESHOLD;

/**
 * 文件媒体工具类，用于处理图片视频等媒体文件
 */
@Slf4j
public class FileMediaUtils {

    // 图片文件扩展名
    private static final Set<String> IMAGE_EXTENSIONS = new HashSet<>(
            Arrays.asList("jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "tiff"));

    // 视频文件扩展名
    private static final Set<String> VIDEO_EXTENSIONS = new HashSet<>(
            Arrays.asList("mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "m4v", "3gp"));

    // 音频文件扩展名
    private static final Set<String> AUDIO_EXTENSIONS = new HashSet<>(
            Arrays.asList("mp3", "wav", "flac", "aac", "ogg", "wma", "m4a"));

    /**
     * 判断文件是否为图片
     *
     * @param fileName 文件名
     * @return 是否为图片
     */
    public static boolean isImage(String fileName) {
        if (StrUtil.isEmpty(fileName)) {
            return false;
        }
        String extension = FileUtil.extName(fileName).toLowerCase();
        return IMAGE_EXTENSIONS.contains(extension);
    }

    /**
     * 判断文件是否为视频
     *
     * @param fileName 文件名
     * @return 是否为视频
     */
    public static boolean isVideo(String fileName) {
        if (StrUtil.isEmpty(fileName)) {
            return false;
        }
        String extension = FileUtil.extName(fileName).toLowerCase();
        return VIDEO_EXTENSIONS.contains(extension);
    }

    /**
     * 判断文件是否为音频
     *
     * @param fileName 文件名
     * @return 是否为音频
     */
    public static boolean isAudio(String fileName) {
        if (StrUtil.isEmpty(fileName)) {
            return false;
        }
        String extension = FileUtil.extName(fileName).toLowerCase();
        return AUDIO_EXTENSIONS.contains(extension);
    }

    /**
     * 判断文件是否为媒体文件（图片、视频、音频）
     *
     * @param fileName 文件名
     * @return 是否为媒体文件
     */
    public static boolean isMediaFile(String fileName) {
        return isImage(fileName) || isVideo(fileName) || isAudio(fileName);
    }

    /**
     * 是否使用 Chevereto 处理的文件（图片和视频）
     *
     * @param fileName 文件名
     * @return 是否使用 Chevereto 处理
     */
    public static boolean isCheveretoSupported(String fileName) {
        return isImage(fileName) || isVideo(fileName);
    }

    /**
     * 压缩图片
     *
     * @param imageData 图片数据
     * @param maxWidth  最大宽度（像素）
     * @param maxHeight 最大高度（像素）
     * @param quality   质量 (0.0-1.0)
     * @return 压缩后的图片数据
     */
    public static byte[] compressImage(byte[] imageData, int maxWidth, int maxHeight, float quality) {
        return compressImage(imageData, maxWidth, maxHeight, quality, 0);
    }

    private static Logger logger = LoggerFactory.getLogger(FileMediaUtils.class);

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb

     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPictureForScale(byte[] imageBytes, long desFileSize, String fileName) {
        if (imageBytes == null || imageBytes.length == 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream).scale(accuracy).outputQuality(accuracy).toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("【图片压缩】imageId={} | 图片原大小={}kb | 压缩后大小={}kb", fileName, srcSize / 1024,
                    imageBytes.length / 1024);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }

        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }

    /**
     * 压缩图片（递归版本）
     *
     * @param imageData 图片数据
     * @param maxWidth  最大宽度（像素）
     * @param maxHeight 最大高度（像素）
     * @param quality   质量 (0.0-1.0)
     * @param recursionDepth 递归深度，用于防止无限递归
     * @return 压缩后的图片数据
     */
    private static byte[] compressImage(byte[] imageData, int maxWidth, int maxHeight, float quality, int recursionDepth) {
        if (ArrayUtil.isEmpty(imageData)) {
            return imageData;
        }
        
        // 防止无限递归，最多压缩5次
        if (recursionDepth >= 5) {
            log.warn("图片压缩已达到最大递归深度({}), 返回当前压缩结果", recursionDepth);
            return imageData;
        }

        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData);
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            BufferedImage originalImage = ImageIO.read(inputStream);
            if (originalImage == null) {
                log.warn("无法读取图片数据，跳过压缩");
                return imageData;
            }

            // 如果原图尺寸已经小于目标尺寸，仅进行质量压缩
            if (originalImage.getWidth() <= maxWidth && originalImage.getHeight() <= maxHeight) {
                Thumbnails.of(originalImage)
                        .scale(1.0)
                        .outputQuality(quality)
                        .toOutputStream(outputStream);
            } else {
                Thumbnails.of(originalImage)
                        .size(maxWidth, maxHeight)
                        .keepAspectRatio(true)
                        .outputQuality(quality)
                        .toOutputStream(outputStream);
            }

            byte[] compressedData = outputStream.toByteArray();
            
            // 检查压缩后的大小是否仍然超过阈值
            if (compressedData.length > DEFAULT_COMPRESS_SIZE_THRESHOLD && quality > 0.3f) {
                // 递减质量系数后再次压缩
                float newQuality = Math.max(0.3f, quality - 0.1f);
                log.info("图片压缩后仍超过大小限制 ({} bytes)，降低质量至 {} 并重新压缩", 
                        compressedData.length, newQuality);
                return compressImage(compressedData, maxWidth, maxHeight, newQuality, recursionDepth + 1);
            }
            
            log.info("图片压缩完成: 原大小={}KB, 压缩后={}KB, 压缩率={}%, 质量={}",
                    imageData.length / 1024, compressedData.length / 1024,
                    (1 - ((float) compressedData.length / imageData.length)) * 100, quality);
                    
            return compressedData;
        } catch (IOException e) {
            log.error("压缩图片失败", e);
            return imageData; // 如果压缩失败，返回原始数据
        }
    }

    /**
     * 压缩视频
     *
     * @param videoData   视频数据
     * @param targetWidth 目标宽度
     * @param videoBitrate 视频比特率 (单位:bps)
     * @param audioBitrate 音频比特率 (单位:bps)
     * @return 压缩后的视频数据
     */
//    public static byte[] compressVideo(byte[] videoData, int targetWidth, int videoBitrate, int audioBitrate) {
//        if (ArrayUtil.isEmpty(videoData)) {
//            return videoData;
//        }
//
//        File tempInputFile = null;
//        File tempOutputFile = null;
//
//        try {
//            // 创建临时文件
//            tempInputFile = File.createTempFile("video_input", ".mp4");
//            tempOutputFile = File.createTempFile("video_output", ".mp4");
//
//            // 写入原始视频数据
//            FileUtil.writeBytes(videoData, tempInputFile);
//
//            // 使用 JavaCV 压缩视频
//            FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(tempInputFile);
//            grabber.start();
//
//            // 计算新的高度，保持纵横比
//            int targetHeight = (int) (targetWidth * grabber.getImageHeight() / (double) grabber.getImageWidth());
//
//            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempOutputFile,
//                    targetWidth, targetHeight, grabber.getAudioChannels());
//
//            // 设置视频参数
//            recorder.setVideoCodec(grabber.getVideoCodec());
//            recorder.setFormat("mp4");
//            recorder.setVideoBitrate(videoBitrate);
//            recorder.setFrameRate(grabber.getFrameRate());
//
//            // 设置音频参数
//            if (grabber.getAudioChannels() > 0) {
//                recorder.setAudioCodec(grabber.getAudioCodec());
//                recorder.setAudioBitrate(audioBitrate);
//                recorder.setSampleRate(grabber.getSampleRate());
//            }
//
//            // 开始录制
//            recorder.start();
//
//            // 处理每一帧
//            Frame frame;
//            while ((frame = grabber.grab()) != null) {
//                recorder.record(frame);
//            }
//
//            // 关闭资源
//            recorder.stop();
//            recorder.release();
//            grabber.stop();
//            grabber.release();
//
//            // 读取压缩后的视频
//            byte[] compressedData = Files.readAllBytes(tempOutputFile.toPath());
//
//            log.info("视频压缩完成: 原大小={}KB, 压缩后={}KB, 压缩率={}%",
//                    videoData.length / 1024, compressedData.length / 1024,
//                    (1 - ((float) compressedData.length / videoData.length)) * 100);
//
//            return compressedData;
//        } catch (Exception e) {
//            log.error("压缩视频失败", e);
//            return videoData; // 如果压缩失败，返回原始数据
//        } finally {
//            // 清理临时文件
//            if (tempInputFile != null && tempInputFile.exists()) {
//                tempInputFile.delete();
//            }
//            if (tempOutputFile != null && tempOutputFile.exists()) {
//                tempOutputFile.delete();
//            }
//        }
//    }

    /**
     * 智能压缩媒体文件（根据文件类型选择合适的压缩方法）
     *
     * @param content  文件内容
     * @param fileName 文件名
     * @return 压缩后的内容
     */
    public static byte[] smartCompressMedia(byte[] content, String fileName) {
        if (ArrayUtil.isEmpty(content) || StrUtil.isEmpty(fileName)) {
            return content;
        }

        // 根据文件类型选择压缩方法
        if (isImage(fileName)) {
            // 图片压缩：最大宽度1920px，质量0.85
            return compressPictureForScale(content, 1024, fileName);
        } else if (isVideo(fileName)) {
            // 视频压缩：720p, 1Mbps视频比特率, 128Kbps音频比特率
//            return compressVideo(content, 1280, 1000000, 128000);
        }

        // 不支持的文件类型直接返回原始内容
        return content;
    }
} 